using System;
using System.Collections.Generic;
using System.Text;

namespace Common.Utilities.DLR
{
    /// <summary></summary>
    public enum EvaluationOperator
    {
        /// <summary></summary>
        Equals=0,
        /// <summary></summary>
        NotEqual=1,
        /// <summary></summary>
        Greater=2,
        /// <summary></summary>
        GreaterOrEqual=3,
        /// <summary></summary>
        Less=4,
        /// <summary></summary>
        LessOrEqual=5,
        /// <summary></summary>
        Contains=6
    }

    /// <summary></summary>
    [Serializable]
    public class Evaluable
    {
        private string _FieldName;
        /// <summary></summary>
        public string FieldName
        {
            get { return _FieldName; }
            set { _FieldName = value; }
        }

        private SimpleDataType _TypeToEvaluate;
        /// <summary></summary>
        public SimpleDataType TypeToEvaluate
        {
            get { return _TypeToEvaluate; }
            set { _TypeToEvaluate = value; }
        }

        private EvaluationOperator _Operator;
        /// <summary></summary>
        public EvaluationOperator Operator
        {
            get { return _Operator; }
            set { _Operator = value; }
        }

        private object _CompareAgainst;
        /// <summary></summary>
        public object CompareAgainst
        {
            get { return _CompareAgainst; }
            set { _CompareAgainst = value; }
        }

        /// <summary></summary>
        public Evaluable(string fieldName, SimpleDataType fieldType, EvaluationOperator op, object compareAgainst)
        {
            if (SimpleDataTypeUtil.ToSimpleDataType(compareAgainst.GetType()) != fieldType)
                throw new Exception("Type mismatch");

            this._FieldName = fieldName;
            this._TypeToEvaluate = fieldType;
            this._CompareAgainst = compareAgainst;
            this._Operator = op;
        }

        /// <summary></summary>
        public Evaluable(string fieldName, Type fieldType, EvaluationOperator op, object compareAgainst)
        {
            SimpleDataType simpleType = SimpleDataTypeUtil.ToSimpleDataType(fieldType);
            if(SimpleDataTypeUtil.ToSimpleDataType(compareAgainst.GetType())!=simpleType)
                throw new Exception("Type mismatch");

            this._FieldName = fieldName;
            this._TypeToEvaluate = simpleType;
            this._CompareAgainst = compareAgainst;
            this._Operator = op;
        }

        /// <summary></summary>
        public bool Evaluate(object fieldValue)
        {
            if(SimpleDataTypeUtil.ToSimpleDataType(fieldValue.GetType())==this._TypeToEvaluate)
            {
                switch(this._TypeToEvaluate)
                {
                    case SimpleDataType.DateTimeType:
                        DateTime thisTime = (DateTime) fieldValue;
                        DateTime otherTime = (DateTime) this._CompareAgainst;
                        switch(this._Operator)
                        {
                            case EvaluationOperator.Equals:
                                return thisTime == otherTime;
                            case EvaluationOperator.Greater:
                                return thisTime > otherTime;
                            case EvaluationOperator.GreaterOrEqual:
                                return thisTime >= otherTime;
                            case EvaluationOperator.Less:
                                return thisTime < otherTime;
                            case EvaluationOperator.LessOrEqual:
                                return thisTime <= otherTime;
                            case EvaluationOperator.NotEqual:
                                return thisTime != otherTime;
                            default:
                                return false;
                        }
                    case SimpleDataType.DecimalNumberType:
                        decimal thisVal = (decimal) fieldValue;
                        decimal otherVal = (decimal) this._CompareAgainst;
                        switch(this._Operator)
                        {
                            case EvaluationOperator.Equals:
                                return thisVal == otherVal;
                            case EvaluationOperator.Greater:
                                return thisVal > otherVal;
                            case EvaluationOperator.GreaterOrEqual:
                                return thisVal >= otherVal;
                            case EvaluationOperator.Less:
                                return thisVal < otherVal;
                            case EvaluationOperator.LessOrEqual:
                                return thisVal <= otherVal;
                            case EvaluationOperator.NotEqual:
                                return thisVal != otherVal;
                            default:
                                return false;
                        }
                    case SimpleDataType.IntNumberType:
                        int thisVal2 = (int) fieldValue;
                        int otherVal2 = (int) this._CompareAgainst;
                        switch (this._Operator)
                        {
                            case EvaluationOperator.Equals:
                                return thisVal2 == otherVal2;
                            case EvaluationOperator.Greater:
                                return thisVal2 > otherVal2;
                            case EvaluationOperator.GreaterOrEqual:
                                return thisVal2 >= otherVal2;
                            case EvaluationOperator.Less:
                                return thisVal2 < otherVal2;
                            case EvaluationOperator.LessOrEqual:
                                return thisVal2 <= otherVal2;
                            case EvaluationOperator.NotEqual:
                                return thisVal2 != otherVal2;
                            default:
                                return false;
                        }
                    case SimpleDataType.TextType:
                        string thisStr = (string) fieldValue;
                        string otherStr = (string) this._CompareAgainst;
                        switch(this._Operator)
                        {
                            case EvaluationOperator.Contains:
                                return thisStr.Contains(otherStr);
                            case EvaluationOperator.Equals:
                                return thisStr.ToLower() == otherStr.ToLower();
                            case EvaluationOperator.Greater:
                                return thisStr.ToLower().CompareTo(otherStr.ToLower()) > 0;
                            case EvaluationOperator.GreaterOrEqual:
                                return thisStr.ToLower().CompareTo(otherStr.ToLower()) >= 0;
                            case EvaluationOperator.Less:
                                return thisStr.ToLower().CompareTo(otherStr.ToLower()) < 0;
                            case EvaluationOperator.LessOrEqual:
                                return thisStr.ToLower().CompareTo(otherStr.ToLower()) <= 0;
                            case EvaluationOperator.NotEqual:
                                return thisStr.ToLower() != otherStr.ToLower();
                            default:
                                return false; 
                        }
                    case SimpleDataType.YesNoType:
                        bool thisBool = (bool) fieldValue;
                        bool otherBool = (bool) this._CompareAgainst;
                        switch(this._Operator)
                        {
                            case EvaluationOperator.Equals:
                                return thisBool == otherBool;
                            case EvaluationOperator.NotEqual:
                                return thisBool != otherBool;
                            default:
                                return false;
                        }
                    default:
                        return false;
                }
            }
            else 
                throw new Exception("Type mismatch");
        }
    }
}
